package com.wstuo.common.security.dao;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;

import org.apache.log4j.Logger;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;

import com.wstuo.common.dao.BaseDAOImplHibernate;
import com.wstuo.common.dto.PageDTO;
import com.wstuo.common.security.dto.LDAPDTO;
import com.wstuo.common.security.dto.LDAPQueryDTO;
import com.wstuo.common.security.dto.UserDTO;
import com.wstuo.common.security.entity.LDAP;
import com.wstuo.common.util.DaoUtils;
import com.wstuo.common.util.ReadConnectionResourcesUtil;
import com.wstuo.common.util.StringUtils;

/**
 * LDAPDAO class
 * 
 * @author will
 * 
 */
public class LDAPDAO extends BaseDAOImplHibernate<LDAP> implements ILDAPDAO {

	private static final Logger LOGGER = Logger.getLogger(LDAPDAO.class);

	/**
	 * findPager(LDAPQueryDTO queryDto)
	 */
	public PageDTO findPager(LDAPQueryDTO queryDto, String sidx, String sord) {
		DetachedCriteria dc = DetachedCriteria.forClass(LDAP.class);
		int start = 0;
		int limit = 0;

		if (queryDto != null) {
			start = queryDto.getStart();
			limit = queryDto.getLimit();

			if (StringUtils.hasText(queryDto.getLdapType())) {
				dc.add(Restrictions.like("ldapType", queryDto.getLdapType(),
						MatchMode.ANYWHERE));
			}

			if (StringUtils.hasText(queryDto.getLdapName())) {
				dc.add(Restrictions.like("ldapName", queryDto.getLdapName(),
						MatchMode.ANYWHERE));
			}

			if (StringUtils.hasText(queryDto.getLdapURL())) {
				dc.add(Restrictions.like("ldapURL", queryDto.getLdapURL(),
						MatchMode.ANYWHERE));
			}
		}
		// 排序
		dc = DaoUtils.orderBy(sidx, sord, dc);
		return super.findPageByCriteria(dc, start, limit);
	}

	/**
	 * List<UserDTO> microsoftLDAP()
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
    public List<UserDTO> microsoftLDAP(LDAPDTO parDto) {
		/*ApplicationContext act = AppliactionBaseListener.ctx;
		AppContext appctx = (AppContext) act.getBean("appctx");
		String lang=appctx.getCurrentLanguage();//获取运用的语言
*/		
		List<UserDTO> listUser = new ArrayList<UserDTO>();
		Hashtable hashEnv = new Hashtable();
		hashEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); // LDAP访问安全级别
		hashEnv.put(Context.SECURITY_PRINCIPAL, parDto.getAdminName()); // AD
																		// User
		hashEnv.put(Context.SECURITY_CREDENTIALS, parDto.getAdminPassword()); // AD
																				// Password
		hashEnv.put(Context.INITIAL_CONTEXT_FACTORY,
				"com.sun.jndi.ldap.LdapCtxFactory");
		hashEnv.put(Context.PROVIDER_URL,
				parDto.getLdapURL() + ":" + parDto.getProt());
		ReadConnectionResourcesUtil rctu = new ReadConnectionResourcesUtil("domain.properties");
		// 异常处理
		try {
			
			LdapContext ctx = new InitialLdapContext(hashEnv, null);
            
            //ctx.setRequestControls(new Control[] { sctl, vctl });
            
			SearchControls searchCtls = new SearchControls();
			searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
			NamingEnumeration answer = ctx.search(parDto.getSearchBase(),
					parDto.getSearchFilter(), searchCtls);
			String decimal = "";
			int i=0;
			while (answer.hasMoreElements()) {
				i++;
				SearchResult sr = (SearchResult) answer.next();
				Attributes attrs = sr.getAttributes();
				UserDTO userDto = new UserDTO();
				try {
					userDto.setLoginName(attrs.get("sAMAccountName").get()
							.toString());
				} catch (Exception e) {
					userDto.setLoginName("");
				}
				
				//System.out.println("正在同步："+userDto.getLoginName());
				String userAccountControl = attrs.get("userAccountControl")
						.get().toString();
				String firstName = rctu.getProperty("firstName");
				String lastName = rctu.getProperty("lastName");

				try {
					userAccountControl = attrs.get("userAccountControl").get().toString();
				} catch (Exception e) {
					userAccountControl = "";
				}
				try {
					userDto.setEmail(attrs.get("mail").get().toString());
				} catch (Exception e) {
					userDto.setEmail("");
				}
				try {
					userDto.setFirstName(attrs.get(firstName).get().toString());
				} catch (Exception e) {
					userDto.setFirstName("");
				}
				try {
					userDto.setLastName(attrs.get(lastName).get().toString());
				} catch (Exception e) {
					userDto.setLastName("");
				}
				try {
					userDto.setMoblie(attrs.get("mobile").get().toString());
				} catch (Exception e) {
					userDto.setMoblie("");
				}
				try {
					userDto.setPhone(attrs.get("telephoneNumber").get()
							.toString());
				} catch (Exception e) {
					userDto.setPhone("");
				}
				try {
					userDto.setOfficeAddress(attrs.get("physicalDeliveryOfficeName").get()
							.toString());
				} catch (Exception e) {
					userDto.setOfficeAddress("");
				}
				try {
					userDto.setPosition(attrs.get("title").get().toString());
				} catch (Exception e) {
					userDto.setPosition("");
				}
				Attribute attr = attrs.get("distinguishedName");
				if (attr != null) {
					String[] dn = attr.toString().split(",");
					String dns = "";
					if (dn.length > 0) {
						for (String str : dn) {
							if (str.indexOf("DC=") != -1
									&& str.indexOf("com") == -1) {
								if (dns.equals(""))
									dns = str.substring(3);
								else
									dns = dns + "." + str.substring(3);
							}
						}
					}
					userDto.setDomain(dns);
					userDto.setDistinguishedName(attr.get().toString());//机构
				}
				if(StringUtils.hasText(userAccountControl)){
					decimal = Integer.valueOf(userAccountControl, 16).toString();// 账号代码十六进制转成十进制
					// 十进制最后一位如果是0和2则当前用户为禁用
					if (decimal.substring(decimal.length() - 1).equals("0")
							|| decimal.substring(decimal.length() - 1).equals("2")) {
						userDto.setUserState(false);
					} else {
						userDto.setUserState(true);
					}
				}else {
					userDto.setUserState(true);
				}
				if (userDto.getLoginName() != null && !userDto.getLoginName().contains("$"))
					listUser.add(userDto);
				
			}
			if("ADSync".equals(parDto.getOptType())){
				LDAP ldap = super.findById(parDto.getLdapId());
				//如果只有一条数据则结束并归零
				if(i==1){
					LOGGER.info("同步结束:::");
					//parDto.setUpdateSum(0);
				}else{
					//每次同步完成后，将已同步的数据保存起来
					ldap.setUpdateSum(ldap.getUpdateSum()+i);
				}
				
			}
			
			
			ctx.close();
		} catch (Exception e) {
			e.printStackTrace();
			LOGGER.error(e);
		}

		return listUser;
	}

	/**
	 * List<UserDTO> linuxLDAP()
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
    public List<UserDTO> linuxLDAP(LDAPDTO parDto) {
		List<UserDTO> listUser = new ArrayList<UserDTO>();
		Hashtable hashEnv = new Hashtable();
		hashEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); // LDAP访问安全级别
		hashEnv.put(Context.SECURITY_PRINCIPAL, parDto.getAdminName()); // 登录名
		hashEnv.put(Context.SECURITY_CREDENTIALS, parDto.getAdminPassword()); // 密码
		hashEnv.put(Context.INITIAL_CONTEXT_FACTORY,
				"com.sun.jndi.ldap.LdapCtxFactory");
		hashEnv.put(Context.PROVIDER_URL,
				parDto.getLdapURL() + ":" + parDto.getProt());
		// 异常处理
		try {
			LdapContext ctx = new InitialLdapContext(hashEnv, null);
			SearchControls searchCtls = new SearchControls();
			// 搜索范围,分为"base"(本节点,SearchControls.OBJECT_SCOPE),"one"(单层,SearchControls.ONELEVEL_SCOPE),""(遍历,SearchControls.SUBTREE_SCOPE)
			searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
			NamingEnumeration answer = ctx.search(parDto.getSearchBase(),
					parDto.getSearchFilter(), searchCtls);
			while (answer.hasMoreElements()) {
				SearchResult sr = (SearchResult) answer.next();
				Attributes attrs = sr.getAttributes();
				UserDTO userDto = new UserDTO();
				try {
					userDto.setLoginName(attrs.get("uid").get().toString());
				} catch (Exception e) {
					userDto.setLoginName(null);
				}

				try {
					userDto.setEmail(attrs.get("mail").get().toString());
				} catch (Exception e) {
					userDto.setEmail("");
				}
				try {
					userDto.setLastName(attrs.get("sn").get().toString());
				} catch (Exception e) {
					userDto.setLastName("");
				}

				try {
					userDto.setMoblie(attrs.get("mobile").get().toString());
				} catch (Exception e) {
					LOGGER.error(e);
				}

				try {
					userDto.setPhone(attrs.get("homephone").get().toString());
				} catch (Exception e) {
					LOGGER.error(e);
				}
				if (userDto.getLoginName() != null && !userDto.getLoginName().contains("$"))
					listUser.add(userDto);
			}

			ctx.close();
		} catch (Exception e) {
			LOGGER.error(e);
		}

		return listUser;
	}

	/**
	 * List<UserDTO> ciscoLDAP()
	 */
	public List<UserDTO> ciscoLDAP(LDAPDTO parDto) {
		List<UserDTO> listUser = new ArrayList<UserDTO>();

		return listUser;
	}

	/**
	 * List<UserDTO> otherLDAP()
	 */
	public List<UserDTO> otherLDAP(LDAPDTO parDto) {
		List<UserDTO> listUser = new ArrayList<UserDTO>();

		return listUser;
	}

	/**
	 * LDAPAuthentication(String usrName, String userPwd,String ldap_url, String
	 * port)
	 */
	public boolean ldapAuthentication(String usrName, String userPwd,
			String ldapURL, String port) {
		boolean result = false;
		Properties props = new Properties();

		props.put(Context.INITIAL_CONTEXT_FACTORY,
				"com.sun.jndi.ldap.LdapCtxFactory");
		props.put(Context.SECURITY_AUTHENTICATION, "simple"); // use simple
																// authentication
																// mechanism
		props.put(Context.SECURITY_CREDENTIALS, userPwd);
		props.put(Context.SECURITY_PRINCIPAL, usrName);
		props.put(Context.PROVIDER_URL, ldapURL + ":" + port);

		try {
			// 建立连接
			new InitialDirContext(props);

			result = true;
		} catch (Exception ex) {
			result = false;
		}

		return result;
	}

	/**
	 * ldapAuthentication(List<LDAPDTO> ldapDtos,String userName, String
	 * password)
	 */
	public boolean ldapAuthentication(List<LDAPDTO> ldapDtos, String userName,
			String password) {
		boolean result = false;

		if (ldapDtos != null) {
			for (LDAPDTO ldapDto : ldapDtos) {
				result = this.ldapAuthentication(userName, password,
						ldapDto.getLdapURL(), ldapDto.getProt());

				if (result) {
					break;
				}
			}
		}

		return result;
	}

}
